﻿#pragma once

#include "WeatherDB.h"
#include "OCMain/Timer.h"

using namespace OCPP;

class WeatherTimer2
{
public:
	using VarNameTuple = std::tuple<
		String,
		String,
		String,
		String,
		String,
		String>;

	WeatherTimer2();
	~WeatherTimer2();

	void start(int duaration);

	void setHistVec(StringVector value) { histVec = value; }
	void setCacheExpiredTime(int value) { cacheExpiredTime = value; }
	void setCachePath(String path) { cachePath = path; }
	void setDataPath1(String path) { dataPath1 = path; }
	void setDataPath2(String path) { dataPath2 = path; }
	void setDataPath3(String path) { dataPath3 = path; }

private:
	bool init();
	void clearCaches(String dataType);

	template<class T>
	void doJobAnal(String& lastDate);

	template<class T>
	void doJobFcst(String& lastDate);

	void doJobHist(String date);
	void doJob3DView();

	template<class T>
	void extractAnal(String path, String cachePath, String date);

	template<class T>
	void extractFcst(String path, String cachePath, String date, String hourFolder);

	std::vector<std::future<void>> makeFutures(NetCDFReader& reader, String& ncFileName, StringMap& configMap, WeatherTimer2::VarNameTuple& vars);
	String cachePath;
	String dataPath1; // 实况
	String dataPath2; // 历史
	String dataPath3; // 预览
	StringVector histVec;
	int duaration = 10;
	int cacheExpiredTime = 7;
	StringMap globalConfigMap;
};


static WeatherTimer2::VarNameTuple varNamesAnal = { "Tracer","rh","temp","wwind" ,"uwind","vwind" };

static WeatherTimer2::VarNameTuple varNamesFcst = { "dbzfct","rhfct","tafct","wfct" ,"ufct","vfct" };

template<class T>
void WeatherTimer2::doJobAnal(String& lastDate)
{
	String dateTypeAnal = T::tableName;
	String date = WeatherUtil::getDateUTC();
	if (lastDate != date)
	{
		lastDate = date;
		clearCaches(dateTypeAnal);
		WeatherDB::clear<T>(WeatherUtil::getDateUTC(cacheExpiredTime + 10), WeatherUtil::getDateUTC(cacheExpiredTime));
	}

	String subDataPath = dateTypeAnal == Anal3kmData::tableName ? "3km/nc/anal" : "1km/nc/anal";

	String todayDataPath1 = joinPath(dataPath1, subDataPath,  date);
	String todayCachePath = joinPath(cachePath, dateTypeAnal, date);
	extractAnal<T>(todayDataPath1, todayCachePath, date);
}

template<class T>
void WeatherTimer2::extractAnal(String path, String cachePath, String date)
{
	size_t count = WeatherDB::countAnal<T>(date);
	if (count >= 24 * 6)
		return;

	StringVector nc3dVec = WeatherUtil::listFileWithExt(path, "_3d.nc");
	if (count == nc3dVec.size())
	{
		return;
	}

	std::vector<T> list;
	StringMap configMap = globalConfigMap;
	configMap[VolumeOptions::Config::NameOutputPath] = cachePath;
	for (const auto& nc3dName : nc3dVec)
	{
		uint64 timeStamp = std::atoll(String(date + nc3dName.substr(0, 6)).c_str());
		T data;
		data.setTimestamp(timeStamp);

		if (WeatherDB::existAnal(data))
			continue;

		String ncFileName = joinPath(path, nc3dName);
		if (FileUtil::sizeOfFile(ncFileName) == 0)
		{
			continue;
		}

		AUTO_TIMER_ELAPSE_MESSAGE(str_format("%s/%s out:%lld Cost Time:", date.c_str(), nc3dName.c_str(), timeStamp));
		NetCDFReader reader;
		if (!reader.open(ncFileName))
		{
			continue;
		}


		std::vector<std::future<void>> futures = makeFutures(reader, ncFileName, configMap, varNamesAnal);
		for (auto& f : futures)
		{
			try {
				f.get();
			}
			catch (...) {
				LOG_ERROR << "unknow error.";
				continue;
			}
		}

		list.emplace_back(std::move(data));
	}

	WeatherDB::insert(std::move(list));
}


template<class T>
void WeatherTimer2::doJobFcst(String& lastDate)
{
	String dateTypeFcst = T::tableName;

	String date = WeatherUtil::getDateUTC();
	if (lastDate != date)
	{
		lastDate = date;
		clearCaches(dateTypeFcst);
		WeatherDB::clear<T>(WeatherUtil::getDateUTC(cacheExpiredTime + 10), WeatherUtil::getDateUTC(cacheExpiredTime));
	}

	String subDataPath = dateTypeFcst == Fcst3kmData::tableName ? "3km/nc/fcst" : "1km/nc/fcst";
	String todayDataPath = joinPath(subDataPath, date);

	StringVector hourPathVec = WeatherUtil::listSubDir(joinPath(dataPath1, todayDataPath));

	for (auto hourFolder : hourPathVec)
	{
		String todayDataPath1 = joinPath(dataPath1, todayDataPath, hourFolder);
		String todayCachePath = joinPath(cachePath, dateTypeFcst, date, hourFolder);
		extractFcst<T>(todayDataPath1, todayCachePath, date, hourFolder);
	}
}

template<class T>
void WeatherTimer2::extractFcst(String path, String cachePath, String date, String hourFolder)
{
	if (hourFolder.length() != 8)
	{
		LOG_ERROR << hourFolder << " error format.";
		return;
	}

	String hourStr = hourFolder.substr(2, 6);

	uint64 g = std::atoi(hourStr.c_str());
	size_t count = WeatherDB::countFcst<T>(g);
	if (count == 13)
	{
		return;
	}

	StringVector nc3dVec = WeatherUtil::listFileWithExt(path, "_3d.nc");
	if (count == nc3dVec.size())
	{
		return;
	}

	std::vector<T> list;
	uint64 dateTimeStamp = WeatherUtil::toTimeTick(date + hourStr);
	StringMap configMap = globalConfigMap;
	configMap[VolumeOptions::Config::NameOutputPath] = cachePath;
	for (const auto& nc3dName : nc3dVec)
	{
		uint64 fileTimeStamp = dateTimeStamp;
		fileTimeStamp += std::atoi(nc3dName.substr(6, 4).c_str());
		fileTimeStamp = std::atoll(WeatherUtil::formatTime(fileTimeStamp).c_str());
		T data;
		data.setG(g);
		data.setTimestamp(fileTimeStamp);

		if (WeatherDB::existFcst(data))
			continue;

		String ncFileName = joinPath(path, nc3dName);
		if (FileUtil::sizeOfFile(ncFileName) == 0)
		{
			continue;
		}

		AUTO_TIMER_ELAPSE_MESSAGE(str_format("%s/%s/%s out:%lld Time Cost:", date.c_str(), hourFolder.c_str(), nc3dName.c_str(), fileTimeStamp));
		NetCDFReader reader;
		if (!reader.open(ncFileName))
		{
			continue;
		}

		auto futures = makeFutures(reader, ncFileName, configMap, varNamesFcst);
		for (auto& f : futures)
		{
			try {
				f.get();
			}
			catch (...) {
				LOG_ERROR << "unknow error.";
				continue;
			}
		}

		list.emplace_back(std::move(data));
	}

	WeatherDB::insert(std::move(list));
}
